package com.example.tass.component;

import cn.hutool.core.io.resource.ClassPathResource;
import com.example.tass.licence.KeyTools;
import com.example.tass.licence.LicenceContent;
import com.example.tass.utils.IPUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;

import java.io.ObjectInputStream;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.Signature;
import java.util.Base64;
import java.util.Date;
import java.util.List;

// @Component
public class MyApplicationRunner implements ApplicationRunner, Ordered {

    private static final Logger log = LoggerFactory.getLogger(MyApplicationRunner.class);
    private static final String KEY_ALGORITHM = "SHA1withRSA";

    @Override
    public void run(ApplicationArguments args) throws Exception {

        // 读取序列化的licence文件，转换成LicenceContent对象
        ObjectInputStream objectInputStream = new ObjectInputStream(new ClassPathResource("licence.lic").getStream());
        LicenceContent licenceContent = (LicenceContent) objectInputStream.readObject();

        //1 验证Licence是否在有效期内
        if (!validateDate(licenceContent)) {
            log.error("Expire: " + licenceContent.getNotAfterTime());
            throw new RuntimeException("License invalid");
        }

        //2 校验IP是否在白名单中
        if (!validateIp(licenceContent)) {
            log.error("IP error, only allow: " + licenceContent.getAllowIp());
            throw new RuntimeException("License invalid");
        }

        // 3. 获取验签用的公钥
        PublicKey publicKey = KeyTools.getPublicKeyFromCer();

        // 2. 读取licence文件，获取签名值
        Signature signature = Signature.getInstance(KEY_ALGORITHM);
        signature.initVerify(publicKey);
        StringBuffer sb = new StringBuffer();
        sb.append(licenceContent.getVendor())
                .append(licenceContent.getUser())
                .append(licenceContent.getOrganization())
                .append(licenceContent.getIssuedTime())
                .append(licenceContent.getNotBeforeTime())
                .append(licenceContent.getNotAfterTime())
                .append(licenceContent.getAllowIp());
        signature.update(sb.toString().getBytes(StandardCharsets.UTF_8));
        boolean verify = signature.verify(Base64.getDecoder().decode(licenceContent.getSign().replaceAll(" ", "+").getBytes(StandardCharsets.UTF_8)));
        System.out.println("Valid licence...");
        if (!verify) {
            throw new RuntimeException("License invalid");
        }
    }

    // 校验时间有效期
    private static boolean validateDate(LicenceContent licenceContent) {
        Date currentTime = new Date();
        if (currentTime.after(licenceContent.getNotAfterTime())) {
            return false;
        } else {
            return true;
        }
    }

    // 校验ip白名单
    private static boolean validateIp(LicenceContent licenceContent) throws SocketException, UnknownHostException {
        List<String> localIps = IPUtils.getLocalIp();
        boolean hasAllowIp = localIps.contains(licenceContent.getAllowIp());
        if (!hasAllowIp) {
            log.warn("Local ip: " + (localIps.size() > 0 ? localIps.get(0) : "fail to find ip"));
        }
        return hasAllowIp;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
